﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
using Eniux.Windows.EnterpriseLibrary.Properties;
using System.Threading;
using System.Windows.Threading;

namespace Eniux.Windows.EnterpriseLibrary.Events
{
    /// <summary>
    /// 事件订阅
    /// </summary>
    /// <typeparam name="TPayload">类型</typeparam>
    public class EventSubscription<TPayload> : IEventSubscription
    {
        #region 变量
		
        private readonly IDelegateReference _actionReference;
        private readonly IDelegateReference _filterReference;
 
	    #endregion

        #region 构造 

        /// <summary>
        /// 构造
        /// </summary>
        /// <param name="actionReference"></param>
        /// <param name="filterReference"></param>
        public EventSubscription(IDelegateReference actionReference, IDelegateReference filterReference,ThreadOption threadOption)
        {
            if (actionReference == null)
                throw new ArgumentNullException("actionReference");
            if (!(actionReference.Target is Action<TPayload>))
                throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Resources.InvalidDelegateRerefenceTypeException, typeof(Action<TPayload>).FullName), "actionReference");

            if (filterReference == null)
                throw new ArgumentNullException("filterReference");
            if (!(filterReference.Target is Predicate<TPayload>))
                throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Resources.InvalidDelegateRerefenceTypeException, typeof(Predicate<TPayload>).FullName), "filterReference");
            this.ThreadOption = threadOption;
            _actionReference = actionReference;
            _filterReference = filterReference;
        } 

        #endregion

        #region 字段 

        public Action<TPayload> Action
        {
            get { return (Action<TPayload>)_actionReference.Target; }
        }


        public Predicate<TPayload> Filter
        {
            get { return (Predicate<TPayload>)_filterReference.Target; }
        }

        public ThreadOption ThreadOption
        {
            get;
            set;
        }
        public SubscriptionToken SubscriptionToken { get; set; } 

        #endregion

        #region 方法

        public virtual Action<object[]> GetExecutionStrategy()
        {
            Action<TPayload> action = this.Action;
            Predicate<TPayload> filter = this.Filter;
            if (action != null && filter != null)
            {
                return arguments =>
                {
                    TPayload argument = default(TPayload);
                    if (arguments != null && arguments.Length > 0 && arguments[0] != null)
                    {
                        argument = (TPayload)arguments[0];
                    }
                    if (filter(argument))
                    {
                        InvokeAction(action, argument);
                    }
                };
            }
            return null;
        }

        public virtual void InvokeAction(Action<TPayload> action, TPayload argument)
        {
            if (action == null) throw new System.ArgumentNullException("action");

            switch (ThreadOption)
            {
                case ThreadOption.PublisherThread:
                    action(argument);
                    break;
                case ThreadOption.UIThread:
                    Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Normal, action, argument);
                    break;
                case ThreadOption.BackgroundThread:
                    ThreadPool.QueueUserWorkItem((o) => action(argument));
                    break;
                default:
                    action(argument);
                    break;
            }
        } 

        #endregion

    }
}
